package com.xingkeduo.business.order.domain;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xingkeduo.business.order.remote.AdminRemoteService;
import com.xingkeduo.business.order.remote.feign.CommentFeignService;
import com.xingkeduo.business.order.service.OrderRefundService;
import com.xingkeduo.dto.ConsumerStatisticsDTO;
import com.xingkeduo.dto.CraftsmanDTO;
import com.xingkeduo.dto.param.DescriptionDto;
import com.xingkeduo.dto.param.StatisticeParam;
import com.xingkeduo.dto.response.*;
import com.xingkeduo.pojo.enums.OrderSource;
import com.xingkeduo.pojo.query.OrderMapper;
import com.xingkeduo.pojo.table.Order;
import com.xingkeduo.pojo.table.OrderRefund;
import com.xingkeduo.utils.DateTimeUtils;
import com.xingkeduo.utils.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
@Transactional
public class DataStatisticsService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private AdminRemoteService adminRemoteService;

    @Resource
    private CommentFeignService commentFeignService;

    @Resource
    private OrderRefundService orderRefundService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
    * @description: 业绩数据
    * @author: ch
    * @Param [statisticeParam]
    * @return com.xingkeduo.dto.response.PerformanceDto
    * @date: 2019-07-16 18:37
    **/
    public PerformanceDto performanceQuery(StatisticeParam statisticeParam){
        PerformanceDto performanceDto = new PerformanceDto();
        //获取当天开始时间
        LocalDateTime startTime = timeTransition(statisticeParam.getDate());
        //获取第二天开始时间
        LocalDateTime endTime = startTime.plusDays(1);
        //获取当月的开始时间
        LocalDateTime monthStartTime = startTime.with(TemporalAdjusters.firstDayOfMonth());
        //获取当天订单
        List<Order> orderDay = orderQuery(statisticeParam.getStoreId(), startTime, endTime);
        //获取当月订单数据
        List<Order> ordersMonth = orderQuery(statisticeParam.getStoreId(), monthStartTime, endTime);
        performanceDto.setDayNum(orderDay.size());
        performanceDto.setMonthNum(ordersMonth.size());
        performanceDto.setDayPrice(addPay(orderDay));
        performanceDto.setMonthPrice(addPay(ordersMonth));
        return performanceDto;
    }


    /**
    * @description: 获取当日业绩详情
    * @author: ch
    * @Param [statisticeParam]
    * @return com.xingkeduo.dto.response.PerformInfosDto
    * @date: 2019-07-17 10:13
    **/
    public PerformInfosDto performanceInfoQuery(StatisticeParam statisticeParam){

        PerformInfosDto performInfosDto = new PerformInfosDto();
        //获取当天开始时间
        LocalDateTime startTime = timeTransition(statisticeParam.getDate());
        //获取第二天开始时间
        LocalDateTime endTime = startTime.plusDays(1);

        //获取当天订单
        List<Order> orderDay = orderQuery(statisticeParam.getStoreId(), startTime, endTime);
        performInfosDto.setOrderCount(orderDay.size());
        performInfosDto.setPerformanceCount(addPay(orderDay));
        List<PerformanceInfoDto> performanceInfoDtos = queryAdminInfo(startTime,endTime,statisticeParam.getStoreId());
        performInfosDto.setPerforms(performanceInfoDtos);
        return performInfosDto;
    }
    
    /**
    * @description: 获取发型师今日业绩
    * @author: ch
    * @Param []
    * @return java.util.List<com.xingkeduo.dto.response.PerformanceInfoDto>
    * @date: 2019-07-17 10:15
    **/
    public List<PerformanceInfoDto> queryAdminInfo( LocalDateTime startTime, LocalDateTime endTime,String storeId){
        //获取今日发型师
        List<Order> orders = queryAdmins(startTime, endTime, storeId);
        List<PerformanceInfoDto> performanceInfoDtos = orders.stream()
                .map((Order order) -> getAdminInfo (order,startTime,endTime,storeId))
                .collect(Collectors.toList());
        return performanceInfoDtos;
    }

    /**
    * @description:
    * @author: ch
    * @Param [order, startTime, endTime, storeId]
    * @return com.xingkeduo.dto.response.PerformanceInfoDto
    * @date: 2019-07-17 11:34
    **/
    public PerformanceInfoDto getAdminInfo(Order order,LocalDateTime startTime, LocalDateTime endTime,String storeId){
        PerformanceInfoDto performanceInfoDto = new PerformanceInfoDto();
        String adminId = order.getAdminId();
        List<Order> orders = adminQuery(adminId, storeId, startTime, endTime);
        CraftsmanDTO craftsmanDTO = queryAdminInfo(adminId);
        performanceInfoDto.setAdminId(String.valueOf(craftsmanDTO.getCode()));
        performanceInfoDto.setDayNum(orders.size());
        performanceInfoDto.setDayPrice(addPay(orders));
        performanceInfoDto.setAdminNickName(craftsmanDTO.getNickName());

        return performanceInfoDto;
    }

    /**
    * @description: 获取发型师昵称
    * @author: ch
    * @Param [performanceInfoDto]
    * @return void
    * @date: 2019-07-17 11:55
    **/
    public String queryAdminNickName(String adminId){
        if (StringUtils.isNotBlank(adminId)) {
            CraftsmanDTO admin = adminRemoteService.getAdmin(adminId);
            if (admin != null) {
              return admin.getNickName();
            }

        }
        return "";
    }


    /**
     * @description: 获取发型师昵称和code
     * @author: ch
     * @Param [performanceInfoDto]
     * @return void
     * @date: 2019-07-17 11:55
     **/
    public CraftsmanDTO queryAdminInfo(String adminId){
        if (StringUtils.isNotBlank(adminId)) {
            CraftsmanDTO admin = adminRemoteService.getAdmin(adminId);
            if (admin != null) {
                return admin;
            }

        }
        return new CraftsmanDTO();
    }
 

    /**
    * @description: 获取今日发型师
    * @author: ch
    * @Param [startTime, endTime, storeId]
    * @return java.util.List<com.xingkeduo.pojo.table.Order>
    * @date: 2019-07-17 10:23
    **/
    public List<Order> queryAdmins(LocalDateTime startTime, LocalDateTime endTime,String storeId){
        //获取今日发型师
        LambdaQueryWrapper<Order> lambda = new QueryWrapper<Order>().lambda();
        lambda.eq(Order::getStoreId,storeId);
        lambda.between(Order::getServeStartTime,startTime,endTime);
        lambda.groupBy(Order::getAdminId);
        return  orderMapper.selectList(lambda);
    }



    /**
    * @description: 计算业绩
    * @author: ch
    * @Param [list]
    * @return java.math.BigDecimal
    * @date: 2019-07-16 20:12
    **/
    public BigDecimal addPay(List<Order> list){
        BigDecimal zero = BigDecimal.ZERO;
        for (Order order:list) {
            zero=zero.add(order.getSubsidiesPrice()!=null?order.getPayPrice().add(order.getSubsidiesPrice()):order.getPayPrice());
        }

        return zero;
    }


    
    /**
    * @description: 查询当天或当月订单
    * @author: ch
    * @Param [storeId, startTime, endTime]
    * @return java.util.List<com.xingkeduo.pojo.table.Order>
    * @date: 2019-07-16 18:37
    **/
    public List<Order> orderQuery(String storeId,LocalDateTime startTime,LocalDateTime endTime){
        LambdaQueryWrapper<Order> lambda = new QueryWrapper<Order>().lambda();
        lambda.eq(Order::getStoreId,storeId);
        lambda.between(Order::getServeStartTime,startTime,endTime);
        return orderMapper.selectList(lambda);
    }


    /**
    * @description: 获取当天开始时间
    * @author: ch
    * @Param [date, hour, minute, second]
    * @return java.time.LocalDateTime
    * @date: 2019-07-16 18:02
    **/
    public static LocalDateTime  timeTransition(String date){
        LocalDate localDate = DateTimeUtils.yyyy_MM_dd(date);
        LocalDateTime of = LocalDateTime.of(localDate, LocalTime.now()).withHour(0).withMinute(0).withSecond(0).withNano(0);
        return of;
    }


    public List<Order> adminQuery(String adminId,String storeId,LocalDateTime startTime,LocalDateTime endTime){
        LambdaQueryWrapper<Order> lambda = new QueryWrapper<Order>().lambda();
        lambda.eq(Order::getStoreId,storeId);
        lambda.between(Order::getServeStartTime,startTime,endTime);
        lambda.eq(Order::getAdminId,adminId);
        return orderMapper.selectList(lambda);
    }


    /**
    * @description: 服务质量查询
    * @author: ch
    * @Param [statisticeParam]
    * @return com.xingkeduo.dto.response.ServiceInfoDto
    * @date: 2019-07-17 14:40
    **/
    public ServiceInfoDto serviceQuery(StatisticeParam statisticeParam) {
        ServiceInfoDto serviceInfoDto = new ServiceInfoDto();
        @NotBlank(message = "门店id不能为空") String storeId = statisticeParam.getStoreId();
        //获取当天开始时间
        LocalDateTime startTime = timeTransition(statisticeParam.getDate());
        //获取第二天开始时间
        LocalDateTime endTime = startTime.plusDays(1);
        ResponseUtils<Map<String,Integer>> commentsResponseUtils = commentFeignService.queryServiceQuality(storeId,startTime,endTime);
        serviceInfoDto.setDayComments(commentsResponseUtils.getData().get("dayComments"));
        serviceInfoDto.setDayNegativeComments(commentsResponseUtils.getData().get("dayNegativeComments"));
        serviceInfoDto.setServiceDelay(orderMapper.selectCount(timeLater(storeId,startTime,endTime)));
        serviceInfoDto.setServiceRefund(orderRefundService.serviceRefund(storeId,startTime,endTime));
        return serviceInfoDto;
    }

    /**
    * @description: 服务质量详情查询
    * @author: ch
    * @Param [statisticeParam]
    * @return java.util.List<com.xingkeduo.dto.response.ServiceDto>
    * @date: 2019-07-17 14:50
    **/
    public ServiceInfoDto serviceInfoQuery(StatisticeParam statisticeParam) {
        ServiceInfoDto serviceInfoDto = serviceQuery(statisticeParam);
        @NotBlank(message = "门店id不能为空") String storeId = statisticeParam.getStoreId();
        //获取当天开始时间
        LocalDateTime startTime = timeTransition(statisticeParam.getDate());
        //获取第二天开始时间
        LocalDateTime endTime = startTime.plusDays(1);
        try {
            ResponseUtils<Set<String>> setResponseUtils = commentFeignService.queryDetailsServiceQuality(storeId, startTime,endTime);
            Set<String> data = setResponseUtils.getData();
            List<Order> orders = orderMapper.selectList(timeLater(storeId,startTime,endTime));
            List<OrderRefund> orderRefunds = orderRefundService.serviceRefundList(storeId,startTime,endTime);
            if (orders.size()!=0) {
                for (int i = 0, length = orders.size(); i < length; i++) {
                    data.add(orders.get(i).getAdminId());
                }
            }
            if (orderRefunds.size()!=0) {
                for (int i = 0, length = orderRefunds.size(); i < length; i++) {
                    data.add(orderRefunds.get(i).getAdminId());
                }
            }
            Iterator<String> iterator = data.iterator();

            List<ServiceInfoDto> serviceInfoDtos = new ArrayList<>();
            while(iterator.hasNext()){
                String adminId = iterator.next();
                ServiceInfoDto serviceInfoDto1 = serviceInfoDto(adminId,storeId, startTime,endTime);
                serviceInfoDtos.add(serviceInfoDto1);
            }
            serviceInfoDto.setServiceInfoDtos(serviceInfoDtos);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return serviceInfoDto;
    }

    /**
     * 服务发型师质量
     * @param adminId
     * @param storeId
     * @param startTime
     * @param endTime
     * @return
     */
    public ServiceInfoDto serviceInfoDto(String adminId,String storeId,LocalDateTime startTime,LocalDateTime endTime){
        ServiceInfoDto serviceInfoDto = new ServiceInfoDto();
        ResponseUtils<Map<String, Integer>> mapResponseUtils1 = commentFeignService.queryDetailsServiceQualityByAdminId(storeId,adminId,startTime,endTime);
        Map<String, Integer> data1 = mapResponseUtils1.getData();
        Integer integer = data1.get("dayCommentsList"); // 发型师指定日期评价数
        Integer integer1 = data1.get("dayNegativeCommentsList"); // 发型师指定日期差评数
        Integer integer2 = orderMapper.selectCount(new QueryWrapper<Order>().lambda()
                .eq(Order::getAdminId, adminId)
                .eq(Order::getStoreId,storeId)
                .between(Order::getServeStartTime, startTime, endTime)
                .ne(Order::getOrderSource,OrderSource.SUI_XING_FU)
                .apply("UNIX_TIMESTAMP(serve_start_time)-UNIX_TIMESTAMP(appointment_start_time)>900")); // 晚点数
        Integer integer3 =orderRefundService.countRefundByAdminId(storeId,adminId,startTime,endTime);
        CraftsmanDTO craftsmanDTO =  queryAdminInfo(adminId);
        String adminNickName = craftsmanDTO.getNickName();
        serviceInfoDto.setAdminId(String.valueOf(craftsmanDTO.getCode()));
        serviceInfoDto.setDayComments(integer);
        serviceInfoDto.setDayNegativeComments(integer1);
        serviceInfoDto.setServiceDelay(integer2);
        serviceInfoDto.setServiceRefund(integer3);
        serviceInfoDto.setAdminNickName(adminNickName);
        return serviceInfoDto;
    }
    
    /**
    * @description:  服务订单来源
    * @author: ch
    * @Param [statisticeParam]
    * @return com.xingkeduo.dto.response.ServiceInfoDto
    * @date: 2019-07-17 14:58
    **/
    public OrderSourceInfoDto sourceQuery(StatisticeParam statisticeParam) {
        //获取当天开始时间
        LocalDateTime startTime = timeTransition(statisticeParam.getDate());
        //获取第二天开始时间
        LocalDateTime endTime = startTime.plusDays(1);
        //获取当天订单
        List<Order> orderDay = orderQuery(statisticeParam.getStoreId(), startTime, endTime);
        OrderSourceInfoDto orderSourceInfoDto = queryServiceInfoDto(orderDay);
        return  orderSourceInfoDto;
        
    }

    /**
    * @description: 订单来源数据统计
    * @author: ch
    * @Param [orders]
    * @return com.xingkeduo.dto.response.OrderSourceInfoDto
    * @date: 2019-07-17 16:10
    **/
    public OrderSourceInfoDto queryServiceInfoDto(List<Order> orders){
        OrderSourceInfoDto orderSourceInfoDto = new OrderSourceInfoDto();
        //指定客
         int designatedCustomer=0;
        // 随行付
         int vbillOrder=0;
        List<ConsumerStatisticsDTO> list  = new ArrayList<>();
        for (Order order:orders) {
            if(order!=null && order.getUserId()!=null){
            ConsumerStatisticsDTO consumerStatisticsDTO = new ConsumerStatisticsDTO();
            consumerStatisticsDTO.setId(Long.valueOf(order.getUserId()));
            consumerStatisticsDTO.setPayTime(DateTimeUtils.yyyy_MM_dd_HH_mm_ss(order.getPayTime()));
            list.add(consumerStatisticsDTO);
            }
        }
        List<ConsumerStatisticsDTO> users= adminRemoteService.queryUserOrderSource(list);
        //新用户
        orderSourceInfoDto.setNewUserOrder(users.size());
        //老用户
        orderSourceInfoDto.setOldUserOrder(orders.size()-orderSourceInfoDto.getNewUserOrder());
        for (Order order:orders) {
            //统计指定客
            if(order.getDesignatedCustomer()!=null && order.getDesignatedCustomer()){
                designatedCustomer++;
            }
            if(OrderSource.SUI_XING_FU.equals(order.getOrderSource())){
                vbillOrder++;
            }
        }
        orderSourceInfoDto.setDesignatedCustomer(designatedCustomer);
        orderSourceInfoDto.setVbillOrder(vbillOrder);
        return orderSourceInfoDto;
    }


    /**
    * @description: 服务订单来源详情
    * @author: ch
    * @Param [statisticeParam]
    * @return com.xingkeduo.dto.response.ServiceInfoDto
    * @date: 2019-07-17 15:00
    **/
    public OrderSourceInfoDto sourceInfoQuery(StatisticeParam statisticeParam) {
        OrderSourceInfoDto serviceInfoDto = sourceQuery(statisticeParam);
        //获取当天开始时间
        LocalDateTime startTime = timeTransition(statisticeParam.getDate());
        //获取第二天开始时间
        LocalDateTime endTime = startTime.plusDays(1);
        serviceInfoDto.setOrderSourceInfos(sourceInfoAdminQuery( startTime,  endTime, statisticeParam.getStoreId()));
        return  serviceInfoDto;
    }

    public List<OrderSourceInfoDto> sourceInfoAdminQuery( LocalDateTime startTime, LocalDateTime endTime,String storeId){
        //获取今日发型师
        List<Order> orders = queryAdmins(startTime, endTime, storeId);

        List<OrderSourceInfoDto> orderSourceInfoDtos = orders.stream()
                .map((Order order) -> getSourceInfo (order,startTime,endTime,storeId))
                .collect(Collectors.toList());
        return orderSourceInfoDtos;
    }




    public OrderSourceInfoDto getSourceInfo(Order order,LocalDateTime startTime, LocalDateTime endTime,String storeId){
        String adminId = order.getAdminId();
        List<Order> orders = adminQuery(adminId, storeId, startTime, endTime);
        OrderSourceInfoDto orderSourceInfoDto = queryServiceInfoDto(orders);
        CraftsmanDTO craftsmanDTO = queryAdminInfo(adminId);
        orderSourceInfoDto.setAdminNickName(craftsmanDTO.getNickName());
        orderSourceInfoDto.setAdminId(String.valueOf(craftsmanDTO.getCode()));
        return orderSourceInfoDto;
    }

    /**
     * 统计服务晚点订单
     * @return
     */
    private LambdaQueryWrapper<Order> timeLater(String storeId,LocalDateTime startTime,LocalDateTime endTime){
        LambdaQueryWrapper<Order> apply = new QueryWrapper<Order>().lambda()
                .eq(Order::getStoreId, storeId)
                .ne(Order::getOrderSource,OrderSource.SUI_XING_FU)
                .between(Order::getServeStartTime, startTime, endTime)
                .apply("UNIX_TIMESTAMP(serve_start_time)-UNIX_TIMESTAMP(appointment_start_time)>900");
        return apply;
    }



    /**
    * @description: 将描述数据添加到redis
    * @author: ch
    * @Param [descriptionDto]
    * @return void
    * @date: 2019-07-19 15:27
    **/
    public void descriptionInfoQuery(List<DescriptionDto> descriptionDto) {
        redisTemplate.opsForValue().set("statistics_description_info",descriptionDto);
    }


    /**
    * @description: 从redis中获取描述信息
    * @author: ch
    * @Param []
    * @return java.util.List<com.xingkeduo.dto.param.DescriptionDto>
    * @date: 2019-07-19 15:38
    **/
    public List<DescriptionDto> descriptionInfo() {
        try {
            List<DescriptionDto> descriptionDto = (List<DescriptionDto>) redisTemplate.opsForValue().get("statistics_description_info");
            log.info("从redis中获取描述信息description{}", JSON.toJSONString(descriptionDto));
            return descriptionDto;
        }catch (Exception e){
            return new ArrayList<>();
        }
    }
}



























